package jp.reflexworks.gdata.util;

import java.io.IOException;
import java.util.logging.Logger;

import com.google.gdata.client.GoogleService.SessionExpiredException;
import com.google.gdata.client.appsforyourdomain.AppsGroupsService;
import com.google.gdata.data.appsforyourdomain.generic.GenericEntry;
import com.google.gdata.data.appsforyourdomain.generic.GenericFeed;
import com.google.gdata.util.ServiceException;
import com.google.gdata.util.AuthenticationException;

public class GoogleAppsProvisioningUtil {
	
	public static final int NUM_RETRIES = 5;
	public static final int SLEEP_MILL_SECOND = 200;

	public static final int CONNECT_TIMEOUT = 30;	// in seconds

	private String appName;
	private String adminUser;
	private String adminPassword;
	private String domain;
	private int connectTimeout = -1;

	Logger logger = Logger.getLogger(this.getClass().getName());

	private AppsGroupsService service = null;

	public GoogleAppsProvisioningUtil(String appName, String adminUser, String adminPassword, String domain) {
		this.appName = appName;
		this.adminUser = adminUser;
		this.adminPassword = adminPassword;
		this.domain = domain;
	}

	public AppsGroupsService login() throws AuthenticationException {
		AppsGroupsService service = null;
		for (int r = 0; r < NUM_RETRIES; r++) {
			try {
				service = new AppsGroupsService(adminUser, adminPassword, domain, appName);
				this.service = service;
				return service;

			} catch (AuthenticationException e) {
				logger.info("AuthenticationException:"+e.getMessage());
				if (r == (NUM_RETRIES - 1)) {
					throw e;
				}
				sleep(SLEEP_MILL_SECOND);
			}
		}
		return null;
	}
	
	public GenericEntry addMemberToGroup(String groupId, String memberName) 
	throws IOException, ServiceException {
		if (service == null) {
			login();
		}

		if (connectTimeout > 0) {
			service.setConnectTimeout(connectTimeout);
		}
		for (int r = 0; r < NUM_RETRIES; r++) {
			try {
				return this.service.addMemberToGroup(groupId, memberName);

			} catch (IOException e) {
				logger.info("IOException:"+e.getMessage());
				if (r == (NUM_RETRIES - 1)) {
					throw e;
				}
				sleep(SLEEP_MILL_SECOND);

			} catch(SessionExpiredException e) {
				logger.info("SessionExpiredException:"+e.getMessage());
				login();

			} catch (ServiceException e) {
				logger.info("ServiceException:"+e.getMessage());
				if (r == (NUM_RETRIES - 1)) {
					throw e;
				}
				sleep(SLEEP_MILL_SECOND);
			}
		}
		return null;
	}
	
	public void deleteMemberFromGroup(String groupId, String memberName) 
	throws IOException, ServiceException {
		if (service == null) {
			login();
		}

		if (connectTimeout > 0) {
			service.setConnectTimeout(connectTimeout);
		}
		for (int r = 0; r < NUM_RETRIES; r++) {
			try {
				this.service.deleteMemberFromGroup(groupId, memberName);
				break;

			} catch (IOException e) {
				logger.info("IOException:"+e.getMessage());
				if (r == (NUM_RETRIES - 1)) {
					throw e;
				}
				sleep(SLEEP_MILL_SECOND);

			} catch(SessionExpiredException e) {
				logger.info("SessionExpiredException:"+e.getMessage());
				login();

			} catch (ServiceException e) {
				logger.info("ServiceException:"+e.getMessage());
				if (r == (NUM_RETRIES - 1)) {
					throw e;
				}
				sleep(SLEEP_MILL_SECOND);
			}
		}
	}
	
	public GenericFeed retrieveAllMembers(String groupId) 
	throws IOException, ServiceException {
		if (service == null) {
			login();
		}

		if (connectTimeout > 0) {
			service.setConnectTimeout(connectTimeout);
		}
		for (int r = 0; r < NUM_RETRIES; r++) {
			try {
				return this.service.retrieveAllMembers(groupId);

			} catch (IOException e) {
				logger.info("IOException:"+e.getMessage());
				if (r == (NUM_RETRIES - 1)) {
					throw e;
				}
				sleep(SLEEP_MILL_SECOND);

			} catch(SessionExpiredException e) {
				logger.info("SessionExpiredException:"+e.getMessage());
				login();

			} catch (ServiceException e) {
				logger.info("ServiceException:"+e.getMessage());
				if (r == (NUM_RETRIES - 1)) {
					throw e;
				}
				sleep(SLEEP_MILL_SECOND);
			}
		}
		return null;
	}
	
	public int getConnectTimeout() {
		return this.connectTimeout;
	}
	
	public void setConnectTimeout(int second) {
		this.connectTimeout = second;
	}

	public synchronized void sleep(long msec) {
		try {
			wait(msec);
		} catch (InterruptedException e) {
		}
	}

}
